/**
This file is part of Gel2DE.

    Gel2DE is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Gel2DE is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Gel2DE.  If not, see <http://www.gnu.org/licenses/>.

	Copyright (C) 2012, University of Bergen
*/

#include "File.h"
#include "StringUtils.h"
#include "direntWin.h"
#include <algorithm>
#include <functional>

namespace gel2de {

File::File(const std::string& path)
   : m_path(expandPath(path))
{
   removeTrailingSlash();   
}

File::File(const File& parent, const std::string& name)
   : m_path(parent.path())
{
   if (!gel2de::endsWith(m_path, "/")) m_path += "/";
   m_path += name;
   removeTrailingSlash();
}

struct FileComparator :  public std::binary_function<const File&, const File&, bool> {
    bool operator()(const File &f1, const File &f2) { if(!(f1.isDirectory()^f2.isDirectory())) return toLowerCase(f1.name())<toLowerCase(f2.name()); else  return f1.isDirectory(); }
    };

void File::listFiles(std::vector<File>& files, FileFilter* fileFilter) const
{
   DIR* dirp = opendir(m_path.c_str());
   if (dirp == 0) return;
   for (;;)
   {
      struct dirent* direntp = readdir(dirp);
      if (direntp == 0) break;
      if (direntp->d_name[0] == '.') continue;
      File file(*this, direntp->d_name);
      if (file.isDirectory() || fileFilter == NULL || fileFilter->accept(file))
      {
         files.push_back(file);
      }
   }
   closedir(dirp);
   std::sort(files.begin(), files.end(), FileComparator());
}

bool File::isDirectory() const
{
   DIR* dirp = opendir(m_path.c_str());
   if (dirp == 0) return false;
   closedir(dirp);
   return true;
}

bool File::exists() const
{
   FILE* f = fopen(m_path.c_str(), "r");
   if (!f) return false;
   fclose(f);
   return true;
}

std::string File::name() const
{
   if (m_path == "/") return "/";
   std::string::size_type i = m_path.rfind('/');
   return (i == std::string::npos) ? m_path : m_path.substr(i + 1);
}

File File::parent() const
{
   if (gel2de::endsWith(m_path, "..")) return File(m_path + "/..");
   std::string::size_type i = m_path.rfind('/');
   if (i == std::string::npos) return File(m_path + "/..");
   return File(i == 0 ? "/" : m_path.substr(0, i));
}

void File::removeTrailingSlash()
{
   if (gel2de::endsWith(m_path, "/") && m_path.size() > 1)
   {
      m_path = m_path.substr(0, m_path.size() - 1);
   }
}

const std::string File::expandPath(const std::string& path)
{

      std::string s = path;
//      std::string *rp = new std::string();
//      std::string& result = *rp;
      std::string result;
      
      while (s.length() > 0)
      {

         std::string::size_type i = s.find_first_of("$");

         if (i == std::string::npos)
         {
            result += s.substr(0);
            break;
         }

         if(i > 0) result += s.substr(0, i-1);
         
         if(i == s.length()-1) break;
         s = s.substr(i+1);
          
         std::string::size_type i0 = s.find_first_of("/");
         std::string::size_type i1 = s.find_first_of(".");
         std::string::size_type i2 = s.find_first_of("$");
         i = i0 < i1 ? (i0 < i2 ? i0 : i2) : (i1 < i2 ? i1 : i2);

         char *cptr = getenv(s.substr(0, i).c_str());
         if(cptr != 0) result += std::string(cptr);

         if(i >= s.length()) break;
         s = s.substr(i);          
      }

   return result;
}

/*****************************************************************************/

FileFilter::~FileFilter()
{
}

/*****************************************************************************/

SuffixFileFilter::~SuffixFileFilter()
{
}

bool SuffixFileFilter::accept(const File& file)
{
   for (int i = 0; i < m_suffixes.size(); i++)
   {
      if (gel2de::endsWith(file.path(), m_suffixes[i]))
      {
         return true;
      }
   }
   return false;
}

} // gel2de::
